/*
 * Copyright (c) 2014 Steve Tracey
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.stevetracey.backup;


import it.sauronsoftware.cron4j.Scheduler;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.stevetracey.backup.io.google.GoogleMail;
import com.stevetracey.common.Configuration;

/**
 * Backup job runner
 * 
 * Runs an initial backup then schedules future backups according
 * to the Cron schedule identified in the configuration file
 * 
 * @author stephen.m.tracey
 *
 */
public class Backup
{

	private static Log log = LogFactory.getLog(Backup.class);

	/** the Cron style schedule to repeat full file synchronisation **/
	private static String FULL_RESYNC_SCHEDULE = Configuration
			.getValue("file.full.resync.cron.schedule");
	
	private static String EMAIL_ADDRESS = Configuration.getValue("file.backup.email.address");
	

	public void startBackup(final BackupJobContext pBackupConfig) 
	{
		log.info("Starting backup of folder [" + pBackupConfig.getFolderName() + "] on local path [" + pBackupConfig.getLocalRoot() + "] to remote path ["
				+ pBackupConfig.getRemoteRoot() + "]");

		FileChangeWatcher watcher = new FileChangeWatcher(pBackupConfig);

		watcher.start();

		log.info("Monitoring this location for changes [" + pBackupConfig.getLocalRoot() + "/" + pBackupConfig.getFolderName() + "]");

		log.info("Performing initial sync of folders for [" + pBackupConfig.getFolderName() + "]");

		BackupWorker backupWorker = new BackupWorker(pBackupConfig);
		backupWorker.run();

		//scheduled re-syncs
		Scheduler scheduler = new Scheduler();
		scheduler.schedule(FULL_RESYNC_SCHEDULE, backupWorker);
		scheduler.start();
		
		log.info("Inital backup complete, further backups according to Cron schedule: " + FULL_RESYNC_SCHEDULE);
	}


	/**
	 * Send a summary email based on the results acculumated in the
	 * BackupJobContext during the run
	 * 
	 * Uses a pre-formatted html email template from the CONF folder
	 * 
	 * @param pBackupData
	 */
	public static void sendSummaryEmail(BackupJobContext pBackupData) {
		
		String status = pBackupData.isRunning() ? "Running" : (pBackupData.getFailedFiles().isEmpty() ? "Success" : "Failures");
		
		//extract all the fields that will be inserted into the email
		Map<String, Object> map = new HashMap<String, Object>();
		
		DecimalFormat format1 = new DecimalFormat("#,###"); 
		DecimalFormat format2 = new DecimalFormat("#,###.##"); 
		
		String machineName = "";
		try 
		{
			machineName = InetAddress.getLocalHost().getHostName();
		}
		catch (UnknownHostException e) {}
		
		map.put("DATE", new Date());
		map.put("MACHINE", machineName);
				
		map.put("STATUS", status);
		map.put("BACKUP_LOCATION_SOURCE", pBackupData.getLocalSourceFolderPath());
		map.put("BACKUP_LOCATION_TARGET", pBackupData.getRemoteFolderPath());
		
		map.put("COUNT_LOCAL_FOLDERS", format1.format(pBackupData.getTotalLocalFolders()));
		map.put("COUNT_LOCAL_FILES", format1.format(pBackupData.getTotalLocalFiles()));
		
		map.put("COUNT_NEW_FILES_SUCCESS", format1.format(pBackupData.getSuccessfulNewFileCount()));
		map.put("COUNT_MOD_FILES_SUCCESS", format1.format(pBackupData.getSuccessfulChangedFileCount()));
		
		map.put("COUNT_FILES_FAILED", format1.format(pBackupData.getFailedFiles().size()));
		
		map.put("SIZE_LOCAL_FOLDERS", format2.format(((double) pBackupData.getTotalLocalBytes()) / 1024 / 1024));
		map.put("SIZE_LOCAL_FILES", format2.format(((double) pBackupData.getTotalLocalBytes())  / 1024 / 1024));
		
		map.put("SIZE_NEW_FILES_SUCCESS", format2.format(((double) pBackupData.getSuccessfulNewFileBytes()) / 1024 / 1024));
		map.put("SIZE_MOD_FILES_SUCCESS", format2.format((double) pBackupData.getSuccessfulChangedFileBytes() / 1024 / 1024));
		
		map.put("SIZE_FILES_FAILED", format2.format(((double) pBackupData.getFailedFileBytes()) / 1024 / 1024));
		
		String failedFiles = "<br/>";
		for (String file : pBackupData.getFailedFiles())
		{
			failedFiles += file + "<br/>";
		}

		if (pBackupData.getFailedFiles().isEmpty()) failedFiles="none";
		
		map.put("FAILED_FILES", failedFiles);
		

		//send the email via Gmail
		log.info("Sending status email to :" + EMAIL_ADDRESS);
		GoogleMail.sendTemplateEmail(EMAIL_ADDRESS, "Backup Report: " + status , map);
		
	}
}
